﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace Project_2
{
    class Program
    {
        /* Developer notes
         * ChangeLog: ( SMALL CHANGES AFTER PRINTOUT PROVIDED TO THE INSTRUCTOR )
         * ****IF A SIGNIFICANT CHANGE IS DONE A NEW PRINTOUT WILL BE PROVIDED.****
         * Some color has been added to specific messages.
         * Will show all age range values even if the value is 0, it would previously show values with more than 0 only
         * Will show all districts population even if the value is 0, it would previously show values with more than 0 only
         * Will display 2 district population per line, it would show 1 district per line.
         * method to create a fake census now adds to lines of invalid data at the beginning of the file to inform that the file was created by the program
         */
        const int DISTSIZE = 22; //IF THIS IS NOT AN EVEN NUMBER THE PROGRAM WILL NOT SHOW THE LAST DISTRICT. THIS WILL BE FIXED IN THE PAID VERSION ONLY.
        const string file = "census.txt";
        static void Main(string[] args)
        {
            //you can not set a constant array :(
            int[] AGEDIF = new int[] { 0, 17, 30, 45, 64 };
            int[] ages = new int[AGEDIF.Length];
            int[] districts = new int[DISTSIZE];
            int totalLines = 0;
            int invalid = 0;
            print("Welcome to Census 2013 Lite information program.\nWith the right provided \"census.txt\" file, this program will return a list of:\nTotal residents of each of the " + DISTSIZE + " districts,\nAnd provide total resident of ages 1-17,18-30,31-45,46-64,and 65 and older.");
            checkFile();
            getDistrictPopulation(AGEDIF, ages, districts, ref invalid, ref totalLines);
            printResults(AGEDIF, ages, districts, invalid, totalLines);
            print("\nThank you for using this program, to donate for the pro version see me in class.\nThe paid version will allow you to type a custom filename, show total of male, female, single and married residents.\nFuture Pro versions will include Social Security Numbers, Addressess, employment info and more!!!\nIts all about the residents privacy..... NOT.\n");
        }

        static void printResults(int[] AGEDIF, int[] ages, int[] districts, int invalid, int totalLines)
        {
            Console.ForegroundColor = ConsoleColor.Red;
            if (totalLines == 0) //if there are no lines in the file...
            {
                print("\nTHE FILE: " + file + " CONTAINS NO DATA.\nDELETE OR REPLEACE WITH A VALID FILE.\n");
                Console.ResetColor();
            }
            else if (totalLines == invalid) //There are lines in the file but all the lines are invalid
            {
                print("\nA CORRUPTED " + file + " FILE HAS BEEN PROVIDED.\nDELETE OR REPLEACE THE FILE.\n");
                Console.ResetColor();
            }
            else //at least 1 line in the file were valid and processed by getDistrictPopulation method
            {
                Console.ResetColor();
                print("\nThe file: " + file + " contained a total of: " + totalLines + " entries with " + invalid + " Invalid Entries.\nInvalid Entries are those missing values or did not contain a valid age or district number.\n");
                Console.ForegroundColor = ConsoleColor.Green;
                for (int i = (AGEDIF.Length - 1); i >= 0; i--)
                {
                    //if (ages[i] > 0) //UNCOMMENT THIS LINE TO ONLY SHOW AGE RANGE WITH > 0 RESIDENTS
                    print(i == (AGEDIF.Length - 1) ? "Total of residents " + (AGEDIF[i] + 1) + " and older in the census are: " + ages[i] : "Total of residents of age " + (AGEDIF[i] + 1) + " to " + AGEDIF[i + 1] + " are: " + ages[i]);
                }
                for (int i = 0; i < districts.Length / 2; i++)
                {
                    //if (districts[i] > 0 || districts[i + districts.Length / 2] > 0) //UNCOMMENT THIS LINE TO ONLY SHOW DISTRICTS WITH > 0 RESIDENTS
                    print("Diststrict " + (i + 1) + " has " + districts[i] + " residents. District " + (1 + districts.Length / 2 + i) + " has " + districts[i + districts.Length / 2] + " residents.");
                }
                Console.ResetColor();
                //print("ANY NON MENTIONED AGE RANGE AND/OR DISTRICTS CONTAIN 0 RESIDENTS.");
            }
        }

        static void getDistrictPopulation(int[] AGEDIF, int[] ages, int[] districts, ref int invalid, ref int totalLines)
        {
            int age = 0, district = 0;
            FileStream cenRead = new FileStream(file, FileMode.Open, FileAccess.Read);
            //it is safer to use "using" segment to reduce the likelyhood of a sintax error
            //this segment has to be iniciated on the StreamReader, NOT the FileStream
            using (StreamReader readCensus = new StreamReader(cenRead))
            {
                string filetext = readCensus.ReadLine();
                while (filetext != null)
                {//split the string and remove empty segments
                    string[] info = filetext.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                    if (info.Length != 4)
                    {//If the data from the file does not contain 4 values divided by a comma it is set as invalid and skiped
                        invalid++;
                        filetext = readCensus.ReadLine();
                    }
                    else if (int.TryParse(info[0], out age) && int.TryParse(info[3], out district) && age > 0 && district > 0 && district <= DISTSIZE)
                    {//If the data contains 4 values divided by a comma, the first and the last value are then evaluated to make sure they are numbers for the age and district
                        int sub = AGEDIF.Length;
                        while (age < AGEDIF[sub - 1])
                            sub--;
                        ages[sub - 1]++;
                        districts[district - 1]++;
                        filetext = readCensus.ReadLine();
                    }
                    else
                    {//if the data contains more than 4 values, or contains no values, or their age and district value is not a valud number it is set as invalid
                        invalid++;
                        filetext = readCensus.ReadLine();
                    }//Options to verify and use data on info[1] ( Gender ) and info[2] ( Marital Status ) can be added after this line
                    totalLines++;
                }
            }
        }

        static void checkFile()
        {
            if (File.Exists(file))
                print("\n" + file + " file has been found in the bin/debug directory and will be used to test the program.\nTo use a different census.txt file, close the program first, replace the file and run the program again.");
            else
            {
                int entries = 0;
                char gender = ' ';
                char status = ' ';
                string writeLine = "";
                Random rand = new Random();
                print("\nA census.txt file has NOT been found in the bin/debug directory,\na FAKE file will be created to TEST the program,\nprovide a number of lines to be written in the file, 1000 or more recommended:");
                while (!int.TryParse(Console.ReadLine(), out entries) || entries < 1)
                    print("\nThe number you have provided is not a Valid number, enter a valid integer. 1000 or more recommended.");
                FileStream fwrite = new FileStream(file, FileMode.Create, FileAccess.Write);
                using (StreamWriter writeFile = new StreamWriter(fwrite))
                {
                    writeLine = "FAKE CENSUS FILE, THIS FIRST 2 LINES WILL BE CONSIDERED INVALID DATA BY THE PROGRAM";
                    writeFile.WriteLine(writeLine);
                    writeLine = "THIS FILE CONTAINS " + entries + " LINES OF DATA, BUT IT CAN BE EDITED AT WILL.";
                    writeFile.WriteLine(writeLine);
                    for (int i = 1; i <= entries; i++)
                    {
                        //Random age from 1 to 100
                        int randAge = rand.Next(1, 101);
                        //Random District from 1 to DISTSIZE
                        int randDis = rand.Next(1, DISTSIZE + 1);
                        //Random gender and status
                        if (rand.Next(1, 3) == 1) gender = 'M';
                        else gender = 'F';
                        if (rand.Next(1, 3) == 1) status = 'M';
                        else status = 'S';
                        writeLine = randAge + "," + gender + "," + status + "," + randDis;
                        writeFile.WriteLine(writeLine);
                    }
                }
                print("\nFake Census File has been created with " + entries + " lines of valid data. You may edit the file at will.");
            }
        }

        static void print(string p)
        {
            Console.WriteLine(p);
        }
    }
}